:- import "%%/lib/hex.sl" #


-- General Mechanisms --

Emit.WriteTo .stream :- set OUTPUT .stream #

Emit.Complete :- unset OUTPUT #

Emit.Reset :- set CURADDRESS 0 #

Emit.Length .cc .len :- list.length .cc .len ! #
Emit.Length . 1 # -- Must be a single byte then

Emit.AddBits (.head, .remains) .offset (.head1, .remains1) :- !
	Emit.AddBits .head .offset .head1,
	Emit.AddBits .remains .offset .remains1 #
Emit.AddBits (+ .dec) .offset (+ .dec1) :-
	int .dec ! let .dec1 (.dec + .offset) #
Emit.AddBits (+ .hex) .offset (+ .dec1) :- !
	Dec.Hex .dec .hex, let .dec1 (.dec + .offset) #
Emit.AddBits .bytes . .bytes #

Emit.Parts $ #
Emit.Parts (.prefix .REX .opcode .opReg .mod .r .RM .S .I .B .disp .imm) :-
	if (not (.prefix = $)) then (
		Emit.CodedBytes .prefix
	),
	if (not (.REX = $)) then (
		Emit.CodedBytes .REX
	),
	if (.opReg = $) then (
		Emit.CodedBytes .opcode
	) else (
		Emit.AddBits .opcode .opReg .opcode1,
		Emit.CodedBytes .opcode1
	),
	if (not (.mod = $)) then (
		Emit.Binary (let ^ (.mod * 64 + .r * 8 + .RM)),
	),
	if (not (.S = $)) then (
		Emit.Binary (let ^ (.S * 64 + .I * 8 + .B)),
	),
	if (not (.disp = $)) then (
		Emit.CodedBytes .disp
	),
	if (not (.imm = $)) then (
		Emit.CodedBytes .imm
	) #

Emit.CodedBytes $ :- ! # -- Haha
Emit.CodedBytes (.head, .remain) :- ! -- List of bytes to generate
	Emit.CodedBytes .head,
	Emit.CodedBytes .remain #
Emit.CodedBytes (+ .byte) :- ! -- Ignores offset prefix at emission
	Emit.CodedBytes .byte #
Emit.CodedBytes (I .size .imm) :- ! -- Fixed-size integer
	Emit.Immediate .size .imm #
Emit.CodedBytes .dec :- -- Integer to byte
	int .dec ! Emit.Binary .dec #
Emit.CodedBytes .hex :- -- String to hex
	Dec.Hex .dec .hex,
	Emit.Binary .dec #

Emit.Immediate 1 .imm :-
	Emit.Binary .imm #
Emit.Immediate 2 .imm :-
	Emit.Binary (let ^ (0 + .imm and 255)),
	Emit.Binary (let ^ (0 + .imm shr 8)) #
Emit.Immediate 4 .imm :-
	Emit.Immediate 2 (let ^ (0 + .imm and 65535)),
	Emit.Immediate 2 (let ^ (0 + .imm shr 16)) #
Emit.Immediate 8 .imm :- -- Upper four bytes nusable!
	Emit.Immediate 4 (let ^ (0 + .imm and 4294967295)),
	Emit.Immediate 4 (let ^ (0 + .imm shr 32)) # -- Till we got 64-bit integers

Emit.Binary .dec :-
	ascii .ch .dec,
	Emit.GetAddress .address, let .a1 (.address + 1), set CURADDRESS .a1,
	whatever ( -- May not output for pass 1
		get OUTPUT .out,
		stream.put .out .ch
	), (
		get PASS 2, -- Testing output
		get HEXDUMP yes,
		Hex2 .dec .hex,
		write .hex;
		yes
	) ! #

Emit.GetAddress .address :- get CURADDRESS .address ! #
